#ifndef THREAD_H_INCLUDED
#define THREAD_H_INCLUDED




















#include <atomic>
#include <bitset>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <vector>

#include "movepick.h"
#include "pawns.h"
#include "position.h"
#include "search.h"
#include "thread_win32.h"




/// Thread struct keeps together all the thread related stuff. We also use
/// per-thread pawn and material hash tables so that once we get a pointer to an
/// entry its life time is unlimited and we don't have to care about someone
/// changing the entry under our feet.

class Thread {

	std::thread nativeThread;
	Mutex mutex;
	ConditionVariable sleepCondition;
	bool exit, searching;

public:
	Thread();
	virtual ~Thread();
	virtual void search();
	void idle_loop();
	void start_searching(bool resume = false);
	void wait_for_search_finished();
	void wait(std::atomic_bool& condition);

	Pawns::Table pawnsTable;
	//Material::Table materialTable;
	//Endgames endgames;
	size_t idx, PVIdx;
	int maxPly, callsCnt;
	uint64_t tbHits;

	Position rootPos;
	Search::RootMoves rootMoves;
	Depth rootDepth;
	Depth completedDepth;
	std::atomic_bool resetCalls;
	CounterMoveStat counterMoves;
	ButterflyHistory history;
	CounterMoveHistoryStat counterMoveHistory;
};


/// MainThread is a derived class with a specific overload for the main thread

struct MainThread : public Thread {
	virtual void search();

	bool easyMovePlayed, failedLow;
	double bestMoveChanges;
	Value previousScore;
};


/// ThreadPool struct handles all the threads-related stuff like init, starting,
/// parking and, most importantly, launching a thread. All the access to threads
/// data is done through this class.

struct ThreadPool : public std::vector<Thread*> {

	void init(); // No constructor and destructor, threads rely on globals that should
	void exit(); // be initialized and valid during the whole thread lifetime.

	MainThread* main() { return static_cast<MainThread*>(at(0)); }
	void start_thinking(Position&, StateListPtr&, const Search::LimitsType&);
	void read_uci_options();
	uint64_t nodes_searched() const;
	uint64_t tb_hits() const;

private:
	StateListPtr setupStates;
};

extern ThreadPool Threads;

#endif // #ifndef THREAD_H_INCLUDED
